package cn.tedu.charging.order.quarz;

import cn.tedu.charging.order.dao.repository.OrderRepository;
import cn.tedu.charging.order.pojo.po.ChargingFailPO;
import cn.tedu.charging.order.pojo.po.ChargingSuccessPO;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.UUID;

/**
 * 设备自检 延迟处理定时任务
 * 目标 尽快发现设备故障
 * 如果没有自检任务,
 * 如果设备无响应,我们无法处理 ,成功订单表和失败订单表都没有数据
 * 如果设备有响应,充了一会,设备故障,走死信队列,发现故障的时长会变长
 * 定时任务 任务的执行时间  当前时间 + 1分钟(设备自检的时间)
 * 如果设备无响应 1分钟就能发现,能快速的通知 用户 通知维修人员
 * 解决 设备开始就没有响应 开始就出故障
 * 死信队列 是检查 最后应该完成,而因为设备故障没有完成的订单  设备开始有响应,中间出故障
 */
@Slf4j
public class DeviceCheckJob implements Job {
    private OrderRepository orderRepository = SpringContextJobUtils.getBean("orderRepositoryImpl", OrderRepository.class);
    public DeviceCheckJob(){}

    public DeviceCheckJob(String orderNo, Integer gunId) throws SchedulerException {
        log.debug("添加设备自检定时任务:订单号:{},枪id:{}", orderNo, gunId);
        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = stdSchedulerFactory.getScheduler();

        JobDetail jobDetail = JobBuilder.newJob(DeviceCheckJob.class)
                .withIdentity("DeviceCheckJob" + UUID.randomUUID(), "device_check_jobs")
                .usingJobData("orderNo", orderNo)
                .usingJobData("gunId", gunId)
                .build();

        Trigger trigger = TriggerBuilder
                .newTrigger().startAt(new Date(System.currentTimeMillis() + 50 * 1000)).build();

        scheduler.scheduleJob(jobDetail,trigger);
        //启动调用器
        scheduler.start();
    }

    /**
     * 执行 干一些事情
     * 7. 判断是否有订单记录
     * 8. 如果有成功订单记录, 不用管, 无需处理,设备有响应的 ,设备给订单服务返回了开始充电成功指令
     * 9. 如果没有成功订单记录,判断是否有失败订单记录,
     * 10. 如果有失败订单记录  设备有响应 设备故障-无法充电,设备给订单返回了开始充电失败指令,  不用管
     * 11. 如果没有失败订单记录 插入失败订单记录, 故障原因 设备无响应
     *
     * @param context
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        String orderNo = jobDataMap.getString("orderNo");
        Integer gunId = jobDataMap.getInt("gunId");

        // 判断成功的订单记录
        ChargingSuccessPO chargingSuccessPO = orderRepository.getSuccessOrder(orderNo);
        if (chargingSuccessPO == null) {
            // 判断失败的订单记录
            ChargingFailPO chargingFailPO = orderRepository.getFailOrder(orderNo);
            if (chargingFailPO == null) {
                // 如果既没有成功订单和失败的订单记录，说明设备自检失败-设备无响应
                // 插入失败的订单记录
                ChargingFailPO newChargingFailPO = new ChargingFailPO();
                newChargingFailPO.setFailDesc("自检失败-设备无响应");
                newChargingFailPO.setBillId(orderNo);
                newChargingFailPO.setGunId(gunId);
                log.debug("设备自检失败，保存失败的订单记录:{}", newChargingFailPO);
                orderRepository.saveFailOrder(newChargingFailPO);
                log.debug("设备自检失败，保存失败的订单记录:{},成功！", newChargingFailPO);

                // 通知设备维修人员
                log.debug("调用保障服务,通知维修人员对设备进行检查和维护,要告诉保障服务，设备信息，或者订单号，然后通过订单号" +
                        "可以反查设备信息！");

                // open-feign和保障服务远程用心
                // 1.创建保障服务微服务
                // 2.创建一个接口，创建维修单的入参
                // 3.创建维修单对应的表
                // id 订单信息(订单id) 设备信息(站id、桩id、枪id) 维修人员id 维修单信息(维修单号、status(新建、完成、修理中)、时间)
                // 4.订单服务增加 保障服务的 feignClient
                // 5. open-feign注入 直接调用

                // rabbitmq消息队列保障服务通信
                // 1.定义保障服务 Exchange 和 queue 并通过 RouteKey 绑定
                // 2.定义保障服务的Producer用来给保障服务饭Exchange发消息
                // 3.消息的格式 {orderNo:"",设备信息:{}}
                // 4.创建保障服务 微服务
                // 5 创建保障服务微服务queue的消费者 @RabbitListener 监听 保障服务的queue
                // 6 生成维修单

                //保障服务 都需要考虑 幂等性,保障同一个订单不能搞出多个维修单

                //生成维修单后,可以让维修师傅来抢单


                //通知充电用户 todo 实时通知用户
                log.debug("通知充电用户,请您更换充电设备,给您带来的不便,请谅解...");
                //给用户发送优惠
                log.debug("调用 营销系统(优惠券服务),给用户发送优惠券 1张价值100元的优惠券已经发放到您的账号，请稍后查收");
                //和调用保障服务类似
            } else {
                // 如果没有成功的订单记录，有失败的订单记录，说明设备自检失败-设备有响应
                log.debug("设备自检失败-设备有响应,但是充不了电,请您更换充电设备,这里逻辑无需修改设备的失败原因");
            }
        } else {
            // 有成功订单记录，表示设备自检成功，有响应，能充电。
            log.debug("有成功订单记录,表示设备自检成功,有响应,能充电");
            log.debug("更新设备信息到订单成功表,枪id:{},订单编号:{},这里不是必须的操作,为了演示,给成功订单表填充设备信息");
            orderRepository.updateDeviceInfo(orderNo, gunId);
            log.debug("更新设备信息到订单成功表成功,枪id:{},订单编号:{},这里不是必须的操作,为了演示,给成功订单表填充设备信息");
        }
    }
}
